Nginx 反向代理到 Tomcat

本篇以鐵人賽「用30天來介紹和使用 Docker 系列」的 Day5: 實作撰寫第一個 Dockerfile 為基礎,記錄我用 nginx 反向代理到 Tomcat 的筆記。

有用過 Docker 的人大概都知道在執行的時候只要指定 port 的 mapping 就可以讓容器與實際 host 的 port 做綁定,這是一般對外 service 類的 container 都會做的設定。

但如果省略掉 port mapping 的步驟,容器中的 Tomcat 就等於是跑在一個內部的環境裡,外部只能透過其它途徑來連線到 Tomcat,某方面來說安全性也會比較高,這邊我就使用最常見的 Nginx 反向代理來連入內部的 Tomcat。

系統環境:CentOS 8.2
自設域名:http://docker(測試子目錄用)
     http://tomcat.docker(測試子網域用,皆以編輯 /etc/hosts 來自訂)

檢測 Tomcat 環境

先依照文章的範例做到第三步驟執行 mytomcat,會發現 Tomcat 執行了,但無法透過本機的 ip 連線,因此必須先查詢容器本身的 ip


查詢 container ID

docker ps -a
# 執行結果:

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
7bdb162641d4        mytomcat            "/apache-tomcat-9.0.…"   6 minutes ago       Up 6 minutes                            musing_gagarin


進入 container 的 shell 裡查詢 IP

docker exec -it musing_gagarin /bin/bash
cat /etc/hosts
# 執行結果

127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters:
172.17.0.2      7bdb162641d4

# 172.17.0.2 就是 tomcat container 的 ip

接著在 host 上連 172.17.0.2:8080 就可以看到 tomcat 頁面

安裝 Nginx

172.17.0.2 是只能在本機上連的內部 ip,外部機器如果也想看到 Tomcat 可以用 Nginx 的反向代理來連線


首先安裝 Nginx 並啟動

sudo dnf install nginx
sudo systemctl enable nginx && sudo systemctl start nginx


開啟防火牆

sudo firewall-cmd --add-service=http --permanent && sudo firewall-cmd --reload


調整 SELinux(如果後面反向代理連線出現 nginx 502 錯誤時使用)

sudo setsebool -P httpd_can_network_connect on

Nginx 反向代理設定

將 nginx 設定檔存到 /etc/nginx/conf.d/myTomcat.conf 後再重啟 nginx 即可,針對不同的域名型態設定內容也會有所不同

使用子網域 http://tomcat.docker

server {
    listen      80;
    server_name tomcat.docker;

    location / {
        proxy_pass http://172.17.0.2:8080/;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Forwarded $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
    }
}
  • proxy_pass 會把 request 轉到 172.17.0.2:8080/,結尾的 / 不要漏掉
  • 幾個 proxy_set_header 與反向代理沒有直接的關係,還沒有特殊需求時可以不用加,但這些設定會影響後端拿到的 header 變數。

使用子目錄 http://docker/tomcat

server {
    listen          80;
    server_name     docker;

    location /tomcat/ {
        proxy_pass http://172.17.0.2:8080/;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Forwarded $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
    }

    location / {
        if ($http_referer ~ "^https?://[^/]+/tomcat/") {
            rewrite ^/(.*) http://$http_host/tomcat/$1 redirect;
        }
    }
}
  • location /tomcat/ 這邊要記得在 tomcat 的結尾加上 / ,不能寫成 /tomcat
  • location / 這段處理子目錄後面的路徑連結,如果沒有加的話,雖然首頁正常,但首頁上的連結點進去還是會失敗


接著試試看用 http://docker/TomCat 來連

由於上面的設定是屬於 case sensitive 的,因此大小寫無法混用

使用子目錄 http://docker/TomCat

server {
    listen          80;
    server_name     docker;

    location ~* /tomcat/(.*) {
        proxy_pass http://172.17.0.2:8080/$1$is_args$args;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Forwarded $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
    }

    location / {
        if ($http_referer ~* "^https?://[^/]+/tomcat/") {
            rewrite ^/(.*) http://$http_host/tomcat/$1 redirect;
        }
    }
}

與前例差在使用了 ~* 來做出 case insensitive(無視大小寫)的功能,讓使用者打錯大小寫也可以連到

參考資料:


nginx proxy to subdirectory

NGINX: Proxy folders to different root

FORM.IO — nginx reversed proxy under ‘subfolder’ in order to host multiple node.js apps

Nginx reverse proxy subdirectory rewrites for sourcegraph

Nginx case insensitive proxy_pass

wade Written by:

本站站長